package com.youlu.campus.web.sign.service.impl;

import com.youlu.campus.base.base.ConstantsEnum;
import com.youlu.campus.base.base.ContentTypeEnum;
import com.youlu.campus.base.base.UserInfo;
import com.youlu.campus.base.certificate.enums.CertificateTypeEnum;
import com.youlu.campus.base.exception.BusinessException;
import com.youlu.campus.base.live.entity.LiveInfo;
import com.youlu.campus.base.sign.SignPlanBase;
import com.youlu.campus.base.sign.SignPlanDetail;
import com.youlu.campus.service.base.BaseService;
import com.youlu.campus.web.common.base.RequestContext;
import com.youlu.campus.web.certificate.CertificateService;
import com.youlu.campus.web.certificate.dto.CertificateSyncRequest;
import com.youlu.campus.web.community.entity.UserFollow;
import com.youlu.campus.web.community.service.InteractiveService;
import com.youlu.campus.web.group.entity.GroupPO;
import com.youlu.campus.web.group.service.GroupRankingListService;
import com.youlu.campus.web.group.service.GroupService;
import com.youlu.campus.web.sign.dto.*;
import com.youlu.campus.web.sign.entity.*;
import com.youlu.campus.web.sign.service.LiveService;
import com.youlu.campus.web.sign.service.SignPlanService;
import com.youlu.campus.entity.UserPO;
import com.youlu.campus.web.common.utils.DateTimeUtils;
import com.youlu.campus.web.common.utils.JsonUtil;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.domain.Page;
import org.springframework.data.domain.PageRequest;
import org.springframework.data.domain.Sort;
import org.springframework.data.mongodb.core.query.Criteria;
import org.springframework.data.mongodb.core.query.Query;
import org.springframework.data.mongodb.core.query.Update;
import org.springframework.data.repository.support.PageableExecutionUtils;
import org.springframework.stereotype.Service;
import org.springframework.util.StringUtils;

import java.util.*;
import java.util.stream.Collectors;

/**
 * @author zgz
 * @date 2020/11/18 16:50
 */
@Slf4j
@Service
public class SignPlanServiceImpl extends BaseService implements SignPlanService {

    @Autowired
    private GroupService groupService;


    @Autowired
    private CertificateService certificateService;

    @Autowired
    private GroupRankingListService groupRankingListService;

    @Autowired
    private LiveService liveService;

    @Autowired
    private InteractiveService interactiveService;

    @Override
    public SignPlanDetailResponse getSignPlanDetail(String signPlanId) {
        String userId = RequestContext.getUserId();
        log.info("getSignPanDetail signPlanId {} userId {}", signPlanId, userId);
        SignPlanPO planPO = mongoTemplate.findById(signPlanId, SignPlanPO.class);
        if (planPO == null || planPO.getDeleted()
                || planPO.getStatus().equals(ConstantsEnum.Status.DISABLED.getCode())) {
            throw new BusinessException("打卡计划不存在或已被删除");
        }
        SignPlanDetailResponse planBase = new SignPlanDetailResponse();
        BeanUtils.copyProperties(planPO, planBase);
        Query query = new Query();
        query.addCriteria(Criteria.where("userInfo.userId").is(userId));
        query.addCriteria(Criteria.where("signPlanId").is(signPlanId));
        query.addCriteria(Criteria.where("deleted").is(false));
        SignPlanJoinPO joinPO = mongoTemplate.findOne(query, SignPlanJoinPO.class);
        if (joinPO != null) {
            List<SignPlanDetailDTO> details = new ArrayList<>();
            List<Long> signDays = mongoTemplate.findDistinct(query, "day", SignPlanDailyPO.class, Long.class);
            int i = 0;
            Long today = DateTimeUtils.getLongDate(new Date());
            for (SignPlanDetail signPlanDetail : planPO.getDetails()) {
                SignPlanDetailDTO detailDTO = new SignPlanDetailDTO();
                BeanUtils.copyProperties(signPlanDetail, detailDTO);
                Long day = DateTimeUtils.getLongDate(DateTimeUtils.addDay(DateTimeUtils.StringToDate(joinPO.getStartDay().toString(),
                        "yyyyMMdd"), i));
                if (signDays.contains(day)) {
                    detailDTO.setSignStatus(1);
                    SignPlanDailyPO dailyPO = this.getSign(userId, signPlanId, day);
                    if (dailyPO != null) {
                        detailDTO.setSignDailyId(dailyPO.getId());
                    }
                } else {
                    if (day < today) {
                        detailDTO.setSignStatus(2);
                    }
                }
                i++;
                LiveResponse response = liveService.queryLive(signPlanId, day.toString());
                if (response != null && !StringUtils.isEmpty(response.getId())) {
                    detailDTO.setLive(true);
                    detailDTO.setLiveId(response.getId());
                }
                details.add(detailDTO);
            }
            planBase.setDetails(details);
        }
        //判断今日是否打卡
        planBase.setSign(this.isSign(userId, signPlanId, DateTimeUtils.getLongDate(new Date())));
        planBase.setJoin(this.getJoinSignPlanInfo(userId, signPlanId) != null);
        return planBase;
    }

    @Override
    public List<SignPlanResponse> getAllSignPlan() {
        String userId = RequestContext.getUserId();
        log.info("getAllSignPlan start");
        Query query = new Query();
        query.addCriteria(Criteria.where("status").is(ConstantsEnum.Status.ENABLED.getCode()));
        query.addCriteria(Criteria.where("deleted").is(false));
        List<SignPlanPO> signPlanPOList = mongoTemplate.find(query, SignPlanPO.class);
        List<SignPlanResponse> responses = new ArrayList<>();
        for (SignPlanPO planPO : signPlanPOList) {
            //判断是否参与过
            if (this.getJoinSignPlanInfo(userId, planPO.getId()) != null) {
                continue;
            }
            SignPlanResponse response = new SignPlanResponse();
            BeanUtils.copyProperties(planPO, response);
            responses.add(response);
        }
        return responses;
    }


    @Override
    public Page<UserInfo> getSignPlanJoinPage(SignPlanJoinPageRequest request) {
        log.info("getSignPlanJoinPage request {}", request);
        Query query = new Query();
        query.addCriteria(Criteria.where("signPlanId").is(request.getSignPlanId()));
        query.addCriteria(Criteria.where("deleted").is(false));
        long count = mongoTemplate.count(query, SignPlanJoinPO.class);
        PageRequest pageRequest = PageRequest.of(request.getPage() - 1, request.getPageSize());
//        query.with(new Sort(Sort.Direction.DESC, "id"));
        Sort sort=Sort.by(Sort.Direction.DESC, "id");
        query.with(sort);
        List<SignPlanJoinPO> signPlanJoinPOList = mongoTemplate.find(query.with(pageRequest), SignPlanJoinPO.class);
        List<UserInfo> list = signPlanJoinPOList.stream().map(signPlanJoinPO -> {
            UserInfo response = new UserInfo();
            BeanUtils.copyProperties(signPlanJoinPO.getUserInfo(), response);
            return response;
        }).collect(Collectors.toList());
        return PageableExecutionUtils.getPage(list, pageRequest, () -> count);
    }

    @Override
    public List<UserInfo> getSignUserList(String signPlanId) {
        log.info("getNewSignList signPlanId {}", signPlanId);
        Query query = new Query();
        query.addCriteria(Criteria.where("signPlanId").is(signPlanId));
        query.addCriteria(Criteria.where("deleted").is(false));
        PageRequest pageRequest = PageRequest.of(0, 20);
//        query.with(new Sort(Sort.Direction.DESC, "id"));
        Sort sort=Sort.by(Sort.Direction.DESC, "id");
        query.with(sort);
        List<SignPlanDailyPO> signPlanDailyPOList = mongoTemplate.find(query.with(pageRequest), SignPlanDailyPO.class);
        return signPlanDailyPOList.stream().map(signPlanDailyPO -> {
            UserInfo response = new UserInfo();
            BeanUtils.copyProperties(signPlanDailyPO.getUserInfo(), response);
            return response;
        }).collect(Collectors.toList());
    }

    @Override
    public List<SignPatchListResponse> getSignPatchList(SignPatchListRequest request) {
        String userId = RequestContext.getUserId();
        log.info("getSignPatchList request {} userId {}", request, userId);
        SignPlanPO planPO = mongoTemplate.findById(request.getSignPlanId(), SignPlanPO.class);
        if (planPO == null || planPO.getDeleted()
                || planPO.getStatus().equals(ConstantsEnum.Status.DISABLED.getCode())) {
            throw new BusinessException("打卡计划不存在或已被删除");
        }
        List<SignPatchListResponse> responseList = new ArrayList<>();
        SignPlanBase planBase = new SignPlanBase();
        BeanUtils.copyProperties(planPO, planBase);
        SignPlanJoinPO joinPO = getJoinSignPlanInfo(userId, request.getSignPlanId());
        if (joinPO != null) {
            Query query = new Query();
            query.addCriteria(Criteria.where("userInfo.userId").is(userId));
            query.addCriteria(Criteria.where("signPlanId").is(request.getSignPlanId()));
            query.addCriteria(Criteria.where("deleted").is(false));
            List<Long> signDays = mongoTemplate.findDistinct(query, "day", SignPlanDailyPO.class, Long.class);
            int i = 0;
            for (SignPlanDetail signPlanDetail : planBase.getDetails()) {
                Long day = DateTimeUtils.getLongDate(DateTimeUtils.addDay(DateTimeUtils.StringToDate(joinPO.getStartDay().toString(),
                        "yyyyMMdd"), i));
                Long today = DateTimeUtils.getLongDate(new Date());
                if(day < today){
                    if (!signDays.contains(day)) {
                        SignPatchListResponse response = new SignPatchListResponse();
                        response.setJobName(signPlanDetail.getJobName());
                        response.setJobAim(signPlanDetail.getJobAim());
                        response.setDay(day);
                        response.setIndex(signPlanDetail.getIndex());
                        responseList.add(response);
                    }
                }else {
                    break;
                }
                i++;
            }
        }
        return responseList;
    }

    @Override
    public Integer joinSignPlan(String signPlanId) {
        UserPO user = RequestContext.getCurUser();
        if (super.resubmit(5L, "joinSignPlan", user.getId(), signPlanId)) {
            throw new BusinessException("请勿频繁点击");
        }
        if (this.getJoinSignPlanInfo(user.getId(), signPlanId) != null) {
            throw new BusinessException("您已加入此打卡计划！");
        }
        //查询打卡计划信息
        SignPlanPO signPlanPO = mongoTemplate.findById(signPlanId, SignPlanPO.class);
        if (signPlanPO == null || signPlanPO.getDeleted()) {
            throw new BusinessException("打卡计划不存在！");
        }
        SignPlanJoinPO joinPO = new SignPlanJoinPO();
        joinPO.setUserInfo(super.getUserInfo(user));
        joinPO.setSignPlanId(signPlanId);
        joinPO.setStartDay(DateTimeUtils.getLongDate(new Date()));
        joinPO.setCreatedTime(new Date());
        mongoTemplate.save(joinPO);
        Query query = new Query(Criteria.where("id").is(signPlanId));
        Update update = new Update();
        update.inc("joinCount");
        update.set("updatedTime", new Date());
        this.mongoTemplate.updateFirst(query, update, SignPlanPO.class);
        //同步证书
        CertificateSyncRequest request = new CertificateSyncRequest();
        request.setCertificateType(CertificateTypeEnum.SIGN_PC);
        BeanUtils.copyProperties(user, request);
        request.setUserId(user.getId());
        request.setSignPlanId(signPlanId);
        certificateService.syncCertificate(request);
        log.info("joinSignPlan userId {} signPlanId {}", user.getId(), signPlanId);
        return 1;
    }

    @Override
    public SignResponse sign(SignPlanRequest request) {
        UserPO user = RequestContext.getCurUser();
        log.info("sign userId {} request {}", user.getId(), request);
        if (super.resubmit(5L, "sign", user.getId(), request.getSignPlanId())) {
            throw new BusinessException("请勿频繁点击");
        }
        Long day = request.getDay();
        if (day == null) {
            day = DateTimeUtils.getLongDate(new Date());
        } else {
            //补卡 判断补卡次数
//            patchCardCountService.patchSignExist();
        }
        //查询是否加入了组织
        GroupPO groupPO = groupService.getJoinGroup(user.getId());
        if (groupPO == null) {
            throw new BusinessException("未查到加入小组信息");
        }
        //查询今天是否已经打卡
        if (this.isSign(user.getId(), request.getSignPlanId(), day)) {
            throw new BusinessException("当天已打卡！");
        }
        //查询打卡计划信息
        SignPlanPO signPlanPO = mongoTemplate.findById(request.getSignPlanId(), SignPlanPO.class);
        if (signPlanPO == null || signPlanPO.getDeleted()) {
            throw new BusinessException("打卡计划不存在！");
        }
        SignPlanJoinPO planJoinPO = this.getJoinSignPlanInfo(user.getId(), request.getSignPlanId());
        if (planJoinPO == null) {
            throw new BusinessException("未查到项目参与信息！");
        }
        if (request.getDay() != null) {
            //扣减补卡机会
//            patchCardCountService.handlePatchSign(user.getId());
        }
        SignPlanDailyPO dailyPO = new SignPlanDailyPO();
        dailyPO.setContent(request.getContent());
        dailyPO.setGroupId(groupPO.getId());
        dailyPO.setDay(day);
        dailyPO.setGroupName(groupPO.getName());
        dailyPO.setCreatedTime(new Date());
        dailyPO.setCreatorId(user.getId());
        dailyPO.setSignPlanId(request.getSignPlanId());
        dailyPO.setPics(request.getPics());
        dailyPO.setUserInfo(super.getUserInfo(user));
        dailyPO.setCreator(groupPO.getUser().getUserId().equals(user.getId()));
        if (!StringUtils.isEmpty(request.getLiveId())) {
            dailyPO.setSignType("live");
            dailyPO.setLiveId(request.getLiveId());
        }
        SignResponse response = new SignResponse();
        for (SignPlanDetail detail : signPlanPO.getDetails()) {
            if (detail.getIndex().equals(request.getIndex())) {
                dailyPO.setJobName(detail.getJobName());
                dailyPO.setJobAim(detail.getJobAim());
                response.setJobName(detail.getJobName());
                break;
            }
        }
        dailyPO.setOpen(request.getOpen());
        dailyPO.setIndex(request.getIndex());
        //维护累计打卡统计数据
        if (!isSign(user.getId(), day)) {
            groupRankingListService.updateUserRank(user.getId(), "sign", 1L, groupPO.getId());
        }
        mongoTemplate.save(dailyPO);
        //维护连续打卡统计数据
        groupRankingListService.updateUserRank(user.getId(), "signSeries", this.getSignSeriesCount(user.getId(), groupPO.getId()), groupPO.getId());
        //维护打卡数量
        Query query = new Query(Criteria.where("id").is(planJoinPO.getId()));
        Update update = new Update();
        update.inc("signCount");
        update.set("updatedTime", new Date());
        this.mongoTemplate.updateFirst(query, update, SignPlanJoinPO.class);
        //维护小组打卡数量
        query = new Query();
        query.addCriteria(Criteria.where("id").is(groupPO.getId()));
        update = new Update();
        update.set("updatedTime", new Date());
        update.inc("signCount");
        mongoTemplate.updateFirst(query, update, GroupPO.class);
        response.setIndex(request.getIndex());
        response.setSignPlanName(signPlanPO.getName());
        handleSignProgress(response, mongoTemplate.findById(planJoinPO.getId(), SignPlanJoinPO.class));
        return response;
    }

    @Override
    public List<SignProgressResponse> getSignProgress() {
        String userId = RequestContext.getUserId();
        log.info("getSignProgress userId {}", userId);
        Query query = new Query();
        query.addCriteria(Criteria.where("userInfo.userId").is(userId));
        query.addCriteria(Criteria.where("deleted").is(false));
        List<SignProgressResponse> responseList = new ArrayList<>();
        List<SignPlanJoinPO> joinPOList = mongoTemplate.find(query, SignPlanJoinPO.class);
        for (SignPlanJoinPO planJoinPO : joinPOList) {
            SignProgressResponse response = new SignProgressResponse();
            SignPlanPO signPlanPO = mongoTemplate.findById(planJoinPO.getSignPlanId(), SignPlanPO.class);
            if (signPlanPO != null) {
                response.setSignPlanName(signPlanPO.getName());
            }
            handleSignProgress(response, planJoinPO);
            //判断今日是否打卡
            response.setSign(this.isSign(userId, planJoinPO.getSignPlanId(), DateTimeUtils.getLongDate(new Date())));
            responseList.add(response);
        }
        return responseList;
    }

    @Override
    public Page<SignPageResponse> getSignPageList(SignPageRequest request) {
        String userId = RequestContext.getUserId();
        log.info("getSignPageList userId {} request {}", userId, request);
        Query query = new Query();
        if (!StringUtils.isEmpty(request.getGroupId())) {
            query.addCriteria(Criteria.where("groupId").is(request.getGroupId()));
        }
        if(request.getType().equals(1)){
            //查询关注人信息
            UserPO user = RequestContext.getCurUser();
            Query q = new Query();
            q.addCriteria(Criteria.where("followerId").is(user.getId()));
            PageRequest pr = PageRequest.of(0, 30);
//            q.with(new Sort(Sort.Direction.DESC, "status"));
            Sort sort=Sort.by(Sort.Direction.DESC, "status");
            q.with(sort);
//            q.with(new Sort(Sort.Direction.DESC, "createdTime"));
            List<UserFollow> follows = mongoTemplate.find(q.with(pr), UserFollow.class);
            if (follows == null || follows.size() <= 0) {
                return PageableExecutionUtils.getPage(new ArrayList<>(), pr, () -> 0);
            }
            Set<String> userIds = follows.stream().map(UserFollow::getUserId).collect(Collectors.toSet());
            log.info("关注人ids:{}", JsonUtil.toJSON(userIds));
            query.addCriteria(Criteria.where("creatorId").in(userIds));
        }
        query.addCriteria(Criteria.where("deleted").is(false));
        query.addCriteria(Criteria.where("displayed").is(true));
        Criteria andOperator = new Criteria().andOperator(Criteria.where("creatorId").is(userId), Criteria.where("open").is(false));
        query.addCriteria(new Criteria().orOperator(andOperator,Criteria.where("open").is(true)));
        long count = mongoTemplate.count(query, SignPlanDailyPO.class);
        PageRequest pageRequest = PageRequest.of(request.getPage() - 1, request.getPageSize());
        if (request.getType().equals(2)) {
//            query.with(new Sort(Sort.Direction.DESC, "hotCount"));
            Sort sort=Sort.by(Sort.Direction.DESC, "hotCount");
            query.with(sort);
//            query.with(new Sort(Sort.Direction.DESC, "createdTime"));
        } else {
//            query.with(new Sort(Sort.Direction.DESC, "createdTime"));
            Sort sort=Sort.by(Sort.Direction.DESC, "createdTime");
            query.with(sort);
        }
        List<SignPlanDailyPO> dailyPOList = mongoTemplate.find(query.with(pageRequest), SignPlanDailyPO.class);
        List<SignPageResponse> list = dailyPOList.stream().map(dailyPO -> {
            SignPageResponse response = mapperFacade.map(dailyPO, SignPageResponse.class);
            //判断当前用户是否组长
            response.setLeader(groupService.isGroupLeader(dailyPO.getGroupId(),dailyPO.getUserInfo().getUserId()));
            //获取计划名称
            SignPlanPO planPO = mongoTemplate.findById(dailyPO.getSignPlanId(), SignPlanPO.class);
            if (planPO != null) {
                response.setSignPlanName(planPO.getName());
            }
            SignPlanJoinPO joinPO = this.getJoinSignPlanInfo(dailyPO.getUserInfo().getUserId(), dailyPO.getSignPlanId());
            if (joinPO != null) {
                response.setSignCount(joinPO.getSignCount());
            }
            response.setLike(interactiveService.queryIsLike(dailyPO.getId(), ContentTypeEnum.DK.getCode()));
            //是否关注
            Query fquery = new Query();
            fquery.addCriteria(Criteria.where("followerId").is(userId));
            fquery.addCriteria(Criteria.where("userId").is(dailyPO.getUserInfo().getUserId()));
            response.setFollow(mongoTemplate.exists(fquery, UserFollow.class));
            //直播信息
            if (!StringUtils.isEmpty(dailyPO.getLiveId())) {
                Query lquery = new Query();
                lquery.addCriteria(Criteria.where("id").is(dailyPO.getLiveId()));
                LiveInfo liveInfo = mongoTemplate.findOne(lquery, LiveInfo.class);
                if (liveInfo != null) {
                    response.setLiveTitle(liveInfo.getTitle());
                    response.setLiveImg(liveInfo.getImg());
                }
            }
            return response;
        }).collect(Collectors.toList());
        return PageableExecutionUtils.getPage(list, pageRequest, () -> count);
    }

    @Override
    public Page<SignPageResponse> getSignRecordList(SignPageRequest request) {
        String userId = RequestContext.getUserId();
        log.info("getSignRecordList userId {} request {}", userId, request);
        Query query = new Query();
        query.addCriteria(Criteria.where("userInfo.userId").is(userId));
        query.addCriteria(Criteria.where("signPlanId").is(request.getSignPlanId()));
        query.addCriteria(Criteria.where("deleted").is(false));
        query.addCriteria(Criteria.where("displayed").is(true));
        long count = mongoTemplate.count(query, SignPlanDailyPO.class);
        PageRequest pageRequest = PageRequest.of(request.getPage() - 1, request.getPageSize());
        List<SignPlanDailyPO> dailyPOList = mongoTemplate.find(query.with(pageRequest), SignPlanDailyPO.class);
        List<SignPageResponse> list = dailyPOList.stream().map(dailyPO -> {
            SignPageResponse response = mapperFacade.map(dailyPO, SignPageResponse.class);
            //获取计划名称
            SignPlanPO planPO = mongoTemplate.findById(dailyPO.getSignPlanId(), SignPlanPO.class);
            if (planPO != null) {
                response.setSignPlanName(planPO.getName());
            }
            return response;
        }).collect(Collectors.toList());
        return PageableExecutionUtils.getPage(list, pageRequest, () -> count);
    }

    @Override
    public SignPageResponse getSignDetail(String id) {
        String userId = RequestContext.getUserId();
        log.info("getSignDetail userId {} id {}", userId, id);
        SignPlanDailyPO dailyPO = mongoTemplate.findById(id, SignPlanDailyPO.class);
        SignPageResponse response = new SignPageResponse();
        if (dailyPO != null) {
            mapperFacade.map(dailyPO,response);
            Query query = new Query();
            query.addCriteria(Criteria.where("id").is(dailyPO.getSignPlanId()));
            SignPlanPO signPlanPO = mongoTemplate.findOne(query, SignPlanPO.class);
            if (Objects.nonNull(signPlanPO)) {
                log.debug(":>>> 打卡计划:{},名字:{}", dailyPO.getSignPlanId(), signPlanPO.getName());
                response.setSignPlanName(signPlanPO.getName());
            }
            SignPlanJoinPO joinPO = this.getJoinSignPlanInfo(dailyPO.getUserInfo().getUserId(), dailyPO.getSignPlanId());
            if (joinPO != null) {
                response.setSignCount(joinPO.getSignCount());
            }
        }

        return response;
    }

    private void handleSignProgress(SignProgressResponse response, SignPlanJoinPO planJoinPO) {
        SignPlanPO signPlanPO = mongoTemplate.findById(planJoinPO.getSignPlanId(), SignPlanPO.class);
        if (signPlanPO == null || signPlanPO.getDeleted()) {
            return;
        }
        response.setSignPlanId(planJoinPO.getSignPlanId());
        response.setSignCount(planJoinPO.getSignCount());
        response.setRemainCount(signPlanPO.getTotalDay() - planJoinPO.getSignCount());

        response.setStartDay(DateTimeUtils.StringToDate(planJoinPO.getStartDay().toString(), "yyyyMMdd"));
        response.setEndDay(DateTimeUtils.addDay(response.getStartDay(), signPlanPO.getTotalDay() - 1));
        //判断是否打卡完成
        long end = DateTimeUtils.getLongDate(response.getEndDay());
        long now = DateTimeUtils.getLongDate(new Date());
        if (end < now) {
            //任务已结束
            response.setEnded(true);
            if(response.getSignCount() >= signPlanPO.getTotalDay()){
                //打卡完成
                response.setMissCount(0);
            }else{
                //获取补卡天数 应打卡天数 - 已打卡天数
                //应打卡天数(算上结束那天)
                long total = DateTimeUtils.getDaysBetween(response.getStartDay(), response.getEndDay())+1;
                response.setMissCount((int)  total - response.getSignCount());
            }
        }else if(end == now){
            //当日任务结束
            if(response.getSignCount() >= signPlanPO.getTotalDay()){
                //当日打卡完成
                response.setMissCount(0);
            }else{
                //当日未完成-查询待补卡天数
                //应打卡天数
                long total = DateTimeUtils.getDaysBetween(response.getStartDay(), new Date());
                if(total > 0){
                    response.setMissCount((int) total  - response.getSignCount());
                }else {
                    response.setMissCount(0);
                }

            }
        }else{
            //任务未结束
            //获取补卡天数
            //应打卡天数（不算今天）
            long total = DateTimeUtils.getDaysBetween(response.getStartDay(), new Date());
            if(total > 0){
                response.setMissCount((int) total  - response.getSignCount());
            }else {
                response.setMissCount(0);
            }

        }
        //获取今日打卡作业信息
        long todayIndex = DateTimeUtils.getDaysBetween(response.getStartDay(), new Date()) + 1;
        for (SignPlanDetail detail : signPlanPO.getDetails()) {
            if (detail.getIndex().equals((int) todayIndex)) {
                response.setJobName(detail.getJobName());
                response.setJobAim(detail.getJobAim());
                response.setIndex(detail.getIndex());
                //获取当前作业打卡人数
                Query query = new Query();
                query.addCriteria(Criteria.where("signPlanId").is(signPlanPO.getId()));
                query.addCriteria(Criteria.where("index").is(response.getIndex()));
                query.addCriteria(Criteria.where("deleted").is(false));
                response.setFinishCount(mongoTemplate.count(query, SignPlanDailyPO.class));
                break;
            }
        }
    }

    private SignPlanJoinPO getJoinSignPlanInfo(String userId, String signPlanId) {
        Query query = new Query();
        query.addCriteria(Criteria.where("userInfo.userId").is(userId));
        query.addCriteria(Criteria.where("signPlanId").is(signPlanId));
        query.addCriteria(Criteria.where("deleted").is(false));
        return mongoTemplate.findOne(query, SignPlanJoinPO.class);
    }

    private boolean isSign(String userId, String signPlanId, Long day) {
        Query query = new Query();
        query.addCriteria(Criteria.where("userInfo.userId").is(userId));
        query.addCriteria(Criteria.where("signPlanId").is(signPlanId));
        query.addCriteria(Criteria.where("day").is(day));
        query.addCriteria(Criteria.where("deleted").is(false));
        return mongoTemplate.exists(query, SignPlanDailyPO.class);
    }

    private SignPlanDailyPO getSign(String userId, String signPlanId, Long day) {
        Query query = new Query();
        query.addCriteria(Criteria.where("userInfo.userId").is(userId));
        query.addCriteria(Criteria.where("signPlanId").is(signPlanId));
        query.addCriteria(Criteria.where("day").is(day));
        query.addCriteria(Criteria.where("deleted").is(false));
        return mongoTemplate.findOne(query, SignPlanDailyPO.class);
    }

    private boolean isSign(String userId, Long day) {
        Query query = new Query();
        query.addCriteria(Criteria.where("userInfo.userId").is(userId));
        query.addCriteria(Criteria.where("day").is(day));
        query.addCriteria(Criteria.where("deleted").is(false));
        return mongoTemplate.exists(query, SignPlanDailyPO.class);
    }

    @Override
    public Long getSignSeriesCount(String userId, String groupId) {
        Query query = new Query();
        query.addCriteria(Criteria.where("userInfo.userId").is(userId));
        query.addCriteria(Criteria.where("groupId").is(groupId));
        query.addCriteria(Criteria.where("deleted").is(false));
//        query.with(new Sort(Sort.Direction.DESC, "day"));
        Sort sort=Sort.by(Sort.Direction.DESC, "day");
        query.with(sort);
        List<Long> days = mongoTemplate.findDistinct(query, "day", SignPlanDailyPO.class, Long.class);
        Long count = 0L;
        for (int i = 0; i < days.size(); i++) {
            Long curDay = DateTimeUtils.getLongDate(DateTimeUtils.addDay(new Date(), -i));
            if (days.get(i).equals(curDay)) {
                count++;
            } else {
                break;
            }
        }
        return count;
    }

    @Override
    public Integer signDailyShare(String id) {
        String userId = RequestContext.getUserId();
        log.info("signDailyShare userId {} id {}", userId, id);
        Query query = new Query();
        query.addCriteria(Criteria.where("id").is(id));
        Update update = new Update();
        update.inc("shareCount");
        update.set("updatedTime", new Date());
        mongoTemplate.updateFirst(query, update, SignPlanDailyPO.class);
        return 1;
    }

    @Override
    public SignPlanCountResponse getSignPlanCount(String signPlanId) {
        String userId = RequestContext.getUserId();
        SignPlanCountResponse response = new SignPlanCountResponse();
        log.info("getSignPlanCount userId {} signPlanId {}", userId, signPlanId);
        SignPlanJoinPO joinPO = this.getJoinSignPlanInfo(userId, signPlanId);
        if (joinPO == null) {
            return response;
        }
        SignPlanPO signPlanPO = mongoTemplate.findById(joinPO.getSignPlanId(), SignPlanPO.class);
        if (signPlanPO == null || signPlanPO.getDeleted()) {
            return response;
        }
        Date startDay = DateTimeUtils.StringToDate(joinPO.getStartDay().toString(), "yyyyMMdd");
        Date endDay = DateTimeUtils.addDay(startDay, signPlanPO.getTotalDay() - 1);
        response.setSignCount(joinPO.getSignCount());
        //判断是否打卡完成
        long end = DateTimeUtils.getLongDate(endDay);
        long now = DateTimeUtils.getLongDate(new Date());
        if (end < now) {
            //任务结束
            if(response.getSignCount() >= signPlanPO.getTotalDay()){
                //打卡完成
                response.setMissCount(0);
            }else{
                //获取补卡天数 应打卡天数 - 已打卡天数
                //应打卡天数(算上结束那天)
                long total = DateTimeUtils.getDaysBetween(startDay, endDay)+1;
                response.setMissCount((int)  total - response.getSignCount());
            }
        }else if(end == now){
            //当日任务结束
            if(response.getSignCount() >= signPlanPO.getTotalDay()){
                //当日打卡完成
                response.setMissCount(0);
            }else{
                //当日未完成-查询待补卡天数
                //应打卡天数
                long total = DateTimeUtils.getDaysBetween(startDay, new Date());
                if(total > 0){
                    response.setMissCount((int) total  - response.getSignCount());
                }else {
                    response.setMissCount(0);
                }

            }
        }else{
            //任务未结束
            //获取补卡天数
            //应打卡天数（不算今天）
            long total = DateTimeUtils.getDaysBetween(startDay, new Date());
            if(total > 0){
                response.setMissCount((int) total  - response.getSignCount());
            }else {
                response.setMissCount(0);
            }

        }
        //项目连续天数
        Query query = new Query();
        query.addCriteria(Criteria.where("userInfo.userId").is(userId));
        query.addCriteria(Criteria.where("signPlanId").is(signPlanId));
        query.addCriteria(Criteria.where("deleted").is(false));
//        query.with(new Sort(Sort.Direction.DESC, "day"));
        Sort sort=Sort.by(Sort.Direction.DESC, "day");
        query.with(sort);
        List<Long> days = mongoTemplate.findDistinct(query, "day", SignPlanDailyPO.class, Long.class);
        Integer count = 0;
        for (int i = 0; i < days.size(); i++) {
            Long curDay = DateTimeUtils.getLongDate(DateTimeUtils.addDay(new Date(), -i));
            if (days.get(i).equals(curDay)) {
                count++;
            } else {
                break;
            }
        }
        response.setSignSeriesCount(count);
        return response;
    }
}
